package com.gitee.yongzhuzl.commonutil.util.wx.official;

import com.gitee.yongzhuzl.commonutil.util.equals.EqualsUtil;
import com.gitee.yongzhuzl.commonutil.util.json.JsonUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.Map;

/**
 * description: 微信公众号文件上传临时文件（主要是图片）工具类
 * @author 朱正磊
 * @date 2020-01-12 16:56:20
 */
public class WxTempUploadUtil {

    private static final Logger log = LoggerFactory.getLogger(WxTempUploadUtil.class);

    /**
     * 文件上传接口地址
     */
    private static final String UPLOAD_URL = "http://file.api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE";

    /**
     * description: 上传本地文件到微信服务器并获取mediaId
     * @param filePath 本地文件存储路径，比如："H:\\images\\fwys.jpg"
     * @param accessToken 调用接口凭证
     * @param type 媒体文件类型，分别有图片（image）、语音（voice）、视频（video）和缩略图（thumb）
     * @return 返回mediaId
     * @throws Exception 异常信息
     * @author 朱正磊
     * @date 2020-01-12 16:58:12
     */
    public static String upload(String filePath, String accessToken, String type) throws Exception {
        // 校验文件是否存在
        File file = new File(filePath);
        // 获取连接
        HttpURLConnection con = getConnection(accessToken, type, file);

        // 设置请求头信息
        con.setRequestProperty("Connection", "Keep-Alive");
        con.setRequestProperty("Charset", "UTF-8");

        // 设置边界
        String boundary = "----------" + System.currentTimeMillis();
        con.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);

        // 拼接请求头信息
        OutputStream out = getOutputStream(boundary, file, con);
        out.close();

        // 读取接口的响应内容
        StringBuilder stringBuilder = new StringBuilder();
        BufferedReader reader = null;
        String result = null;
        try {
            //定义BufferedReader输入流来读取URL的响应
            reader = new BufferedReader(new InputStreamReader(con.getInputStream()));
            String line;
            while ((line = reader.readLine()) != null) {
                stringBuilder.append(line);
            }
            result = stringBuilder.toString();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        } finally {
            if (reader != null) {
                reader.close();
            }
        }

        Map<String, Object> resResult = JsonUtil.toMap(result, String.class, Object.class);
        // 比如：{type=image, media_id=h32WtqZfXHKotMC3t42RiyLbS8P7efMPf3CrETbfCFILaVdTvvWKDR3ewlevujUs, created_at=1578825624, item=[]}
        log.info("调用上传文件到微信服务器接口响应数据：{}", resResult);

        // 获取多媒体文件类型
        String typeName = "media_id";
        if (EqualsUtil.isEquals(type, "thumb")) {
            typeName = "thumb_media_id";
        }

        // 获取多媒体文件ID
        assert resResult != null;
        String mediaId = resResult.get(typeName).toString();
        // 比如：h32WtqZfXHKotMC3t42RiyLbS8P7efMPf3CrETbfCFILaVdTvvWKDR3ewlevujUs
        log.info("多媒体文件ID：{}", mediaId);
        return mediaId;
    }

    /**
     * description: 获取连接
     * @author 朱正磊
     * @date 2025-08-30 14:22:31
     * @param accessToken 调用接口凭证
     * @param type 媒体文件类型
     * @param file 文件
     * @return 返回连接
     */
    private static HttpURLConnection getConnection(String accessToken, String type, File file) throws Exception {
        if (!file.exists() || !file.isFile()) {
            throw new Exception("文件不存在！");
        }

        // 封装请求的url地址
        String url = UPLOAD_URL.replace("ACCESS_TOKEN", accessToken).replace("TYPE", type);
        URI uri = new URI(url);
        URL urlObj = uri.toURL();

        // 打开连接
        HttpURLConnection con = (HttpURLConnection) urlObj.openConnection();

        // 设置连接属性
        con.setRequestMethod("POST");
        con.setDoInput(true);
        con.setDoOutput(true);
        con.setUseCaches(false);
        return con;
    }

    /**
     * description: 获取输出流
     * @author 朱正磊
     * @date 2025-08-30 13:38:15
     * @param boundary 边界
     * @param file 文件对象
     * @param con 连接信息
     * @return 返回输出流
     * @throws IOException 异常信息
     */
    private static OutputStream getOutputStream(String boundary, File file, HttpURLConnection con) throws IOException {
        String builder = "--" +
                boundary +
                "\r\n" +
                "Content-Disposition: form-data;name=\"file\";filename=\"" +
                file.getName() + "\"\r\n" +
                "Content-Type:application/octet-stream\r\n\r\n";
        byte[] head = builder.getBytes(StandardCharsets.UTF_8);

        // 获得输出流
        OutputStream out = new DataOutputStream(con.getOutputStream());

        // 输出表头
        out.write(head);

        // 文件正文部分
        // 把文件以流文件的方式推入到url中
        DataInputStream inputStream = new DataInputStream(Files.newInputStream(file.toPath()));
        return getOutputStream(boundary, inputStream, out);
    }

    /**
     * 温馨提示：上传临时素材
     * description: 模拟form表单的形式上传文件，以输出流的形式把文件写入到url中，然后用输入流来获取url的响应
     * @author 朱正磊
     * @date 2020-01-13 14:41:32
     * @param filePath 文件在服务器保存路径，比如：<a href="https://dmszzl.mynatapp.cc/ddwashcar/file/image/fwys.jpg">...</a>
     * @param accessToken 调用接口凭证
     * @param type 媒体文件类型，分别有图片（image）、语音（voice）、视频（video）和缩略图（thumb）
     * @return 返回接口的响应信息
     */
    public static String uploadFile(String filePath, String accessToken, String type) {
        String result;
        InputStream inputStream;
        BufferedReader reader = null;
        try {
            // 获取输入流
            inputStream = getInputStream(filePath);

            // 获取连接
            HttpURLConnection con = getHttpURLConnection(accessToken, type);

            // 设置关键值
            // 以Post方式提交表单，默认get方式
            con.setRequestMethod("POST");
            con.setDoInput(true);
            con.setDoOutput(true);
            // post方式不能使用缓存
            con.setUseCaches(false);

            // 设置请求头信息
            con.setRequestProperty("Connection", "Keep-Alive");
            con.setRequestProperty("Charset", "UTF-8");

            // 设置边界
            String boundary = "---------------------------" + System.currentTimeMillis();
            con.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);

            OutputStream out = getOutputStream(filePath, boundary, con, inputStream);
            out.close();

            StringBuilder buffer = new StringBuilder();
            // 定义BufferedReader输入流来读取URL的响应
            reader = new BufferedReader(new InputStreamReader(con.getInputStream()));
            String line;
            while ((line = reader.readLine()) != null) {
                buffer.append(line);
            }
            result = buffer.toString();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return null;
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                }
            }
        }
        return result;
    }

    /**
     * description: 获取连接
     * @author 朱正磊
     * @date 2025-08-30 14:08:49
     * @param accessToken 调用接口凭证
     * @param type 媒体文件类型
     * @return 返回连接
     */
    private static HttpURLConnection getHttpURLConnection(String accessToken, String type) throws URISyntaxException, IOException {
        // 请求地址，微信接口地址
        String url = UPLOAD_URL.replace("ACCESS_TOKEN", accessToken).replace("TYPE", type);
        URI uri2 = new URI(url);
        URL urlObj = uri2.toURL();
        return (HttpURLConnection) urlObj.openConnection();
    }

    /**
     * description: 获取输入流
     * @author 朱正磊
     * @date 2025-08-30 14:07:08
     * @param filePath 文件在服务器保存路径
     * @return 返回输入流
     */
    private static InputStream getInputStream(String filePath) throws URISyntaxException, IOException {
        URI uri1 = new URI(filePath);
        URL urlFile = uri1.toURL();
        HttpURLConnection downloadCon = (HttpURLConnection) urlFile.openConnection();
        return downloadCon.getInputStream();
    }

    /**
     * description: 获取输出流
     * @author 朱正磊
     * @date 2025-08-30 13:37:56
     * @param filePath 文件在服务器保存路径，比如：<a href="https://dmszzl.mynatapp.cc/ddwashcar/file/image/fwys.jpg">...</a>
     * @param boundary 边界
     * @param con 连接信息
     * @param inputStream 输入流
     * @return 返回输出流
     * @throws IOException 异常信息
     */
    private static OutputStream getOutputStream(String filePath, String boundary, HttpURLConnection con, InputStream inputStream) throws IOException {
        // 请求正文信息
        // 第一部分：
        String regex = ".*/([^.]+)";
        // 必须多两道线
        String sb = "--" +
                boundary +
                "\r\n" +
                "Content-Disposition: form-data;name=\"media\";filename=\"" + filePath.replaceAll(regex, "$1") + "\"\r\n" +
                "Content-Type:application/octet-stream\r\n\r\n";

        byte[] head = sb.getBytes(StandardCharsets.UTF_8);

        // 获得输出流
        OutputStream out = new DataOutputStream(con.getOutputStream());

        // 输出表头
        out.write(head);

        // 文件正文部分
        // 把文件已流文件的方式 推入到url中
        return getOutputStream(boundary, inputStream, out);
    }

    /**
     * description: 获取输出流
     * @author 朱正磊
     * @date 2025-08-30 13:44:58
     * @param boundary 边界
     * @param inputStream 输入流
     * @param out 输出流
     * @return 返回输出流
     * @throws IOException 异常信息
     */
    private static OutputStream getOutputStream(String boundary, InputStream inputStream, OutputStream out) throws IOException {
        int bytes;
        byte[] bufferOut = new byte[1024];
        while ((bytes = inputStream.read(bufferOut)) != -1) {
            out.write(bufferOut, 0, bytes);
        }
        inputStream.close();

        // 结尾部分
        // 定义最后数据分隔线
        byte[] foot = ("\r\n--" + boundary + "--\r\n").getBytes(StandardCharsets.UTF_8);
        out.write(foot);
        out.flush();
        return out;
    }

}
